package common.util;

import cn.hutool.core.util.ReflectUtil;
import com.google.common.collect.Lists;
import common.config.exception.CustomException;
import org.springframework.util.ObjectUtils;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class ListUtil {

	private ListUtil() {
		throw new AssertionError("不可实例化");
	}

	/**
	 * 对 tList 中的对象根据 fieldName 字段去重，如果重复，保留下标更大的元素
	 *
	 * @return 新的 List，不改变原有的 tList
	 */
	public static <T> List<T> deduplication(List<T> tList, String fieldName) {
		if (tList.isEmpty()) {
			return Lists.newArrayList();
		}
		if (tList.size() == 1) {
			return Lists.newArrayList(tList.get(0));
		}
		if (!ReflectUtil.hasField(tList.get(0).getClass(), fieldName)) {
			throw new CustomException("无效字段名");
		}
		Map<Object, T> map = new LinkedHashMap<>();
		tList.forEach(item -> map.put(ReflectUtil.getFieldValue(item, fieldName), item));
		return Lists.newArrayList(map.values());
	}

	/**
	 * 检测两个 List 的内容是否完全相同，元素顺序影响结果
	 * 相同返回 true，不同返回 false
	 */
	public static boolean checkListDuplicate(List<?> list1, List<?> list2) {
		if (list1.size() != list2.size()) {
			return false;
		} else {
			boolean allTheSame = true;
			for (int i = 0; i < list1.size(); i++) {
				if (!ObjectUtils.nullSafeEquals(list1.get(i), list2.get(i))) {
					allTheSame = false;
					break;
				}
			}
			return allTheSame;
		}
	}

	/**
	 * 检测多个 List 中是否存在内容完全相同的 List，元素顺序影响结果
	 * 存在返回 true，不存在返回 false
	 */
	public static boolean checkDuplicate(List<List<?>> list) {
		for (int i = 0; i < list.size(); i++) {
			List<?> checkingList = list.get(i);
			if (i == 0) {
				continue;
			}
			for (int j = 0; j < i; j++) {
				if (checkListDuplicate(checkingList, list.get(j))) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 去重（不改变原有的 List）
	 */
	public static List<List<?>> removeDuplication(List<List<?>> list) {
		List<List<?>> deduplicatedList = Lists.newArrayList();
		for (int i = 0; i < list.size(); i++) {
			List<?> checkingList = list.get(i);
			if (i == 0) {
				deduplicatedList.add(checkingList);
				continue;
			}
			if (deduplicatedList.stream().noneMatch(item -> checkListDuplicate(checkingList, item))) {
				deduplicatedList.add(checkingList);
			}
		}
		return deduplicatedList;
	}

}
